#include "sock.hpp"
#include "common.hpp"
#include "addr.hpp"
using ioserver = function<void(shared_ptr<Socket> &sk,inetaddr client  )>;//完成的回调函数：协议（怎么接受/处理/发送） unique_ptr不支持拷贝/要么引用要么move
class tcpserver
{
public:
    tcpserver(uint16_t port) : _port(port), _isrunning(0),_listenfd(make_unique<Tcpsocket>())
    {
        _listenfd->arrangesock(port);
    }

    void start(ioserver service)
    {      _isrunning=1;
        while (_isrunning)
        {
            inetaddr addr;//这里addr提供个默认无参构造；不能传指针去改变->inetaddr *ptr-->没初始化是nullptr-->Accept内部非法访问
            shared_ptr<Socket> tcpwrsock = _listenfd->Accept(&addr);//拿到w+r时候的套接字
            if (!tcpwrsock) continue;

             //1·单进程实现测试session功能：
             //不过这里由于是一个进程完成的任务，可能存在当这个进程持续进行某个加载时候，当浏览器再次发送请求，将无法应答，但是这里我们就是为了测试这个
             //session足够了，如果不应用这个session就可以多进程（很好），否则可以考虑改成多线程，线程池等！！！
           // service(tcpwrsock,addr);//回调去协议处：完成接收执行发生的任务

            //2`多进程实现：
            //多进程测试session，由于写实拷贝存在bug！！！
            int id = fork();
            if (id < 0)
            {
                use_log(loglevel::DEBUG) << " fork failure!";

                exit(FORK_ERR);
            }
            else if (id == 0)
            {
                _listenfd-> Close();
                int iid = fork();
                if (iid == 0) {
                
                    service(tcpwrsock,addr);//回调去协议处：完成接收执行发生的任务
                    tcpwrsock->Close();//孙子进程得知客户端退出或者出错就关闭对应fd
                }
                //孙子进程进行按照协议处理工作
                   //这里因为unique_ptr不支持拷贝因此可以引用传给unique/要么就move掉unique的资源给unique/shared；
                   //move后此时tcpwrsock为空；资源直接给了形参shared_ptr了
                exit(OK);
            }
            else
            {
                tcpwrsock->Close();
                pid_t n = waitpid(id, nullptr, 0);
                (void)n;
            }
        }
          _isrunning=0;
          _listenfd->Close();
    }
    ~tcpserver() {}

private:
    bool _isrunning;
    uint16_t _port;
    unique_ptr<Socket> _listenfd;
};